﻿namespace SugarTank.Mobile.ViewModels
{
    using System;
    using System.Collections.Generic;
    using System.Device.Location;
    using System.Windows;
    using System.Windows.Input;
    using CommonTypes.Attributes;
    using CommonTypes.Constants;
    using CommonTypes.Phone;
    using Content.Resources;
    using GalaSoft.MvvmLight;
    using GalaSoft.MvvmLight.Command;
    using GalaSoft.MvvmLight.Threading;
    using Helpers;
    using Managers.Contracts;

    public class MainViewModel : ViewModelBase
    {
        /// <summary>
        /// The injected content manager.
        /// </summary>
        private readonly IContentManager contentManager;

        /// <summary>
        /// The geographic manager.
        /// </summary>
        private readonly IGeographicManager geographicManager;

        /// <summary>
        /// The media manager.
        /// </summary>
        private readonly IMediaManager mediaManager;

        /// <summary>
        /// The resources manager.
        /// </summary>
        private readonly IResourceManager resourceManager;

        /// <summary>
        /// Is currently tracking location.
        /// </summary>
        private bool isTrackingLocation;

        /// <summary>
        /// Is currently recording.
        /// </summary>
        private bool isRecording;

        /// <summary>
        /// Initializes a new instance of the <see cref="MainViewModel"/> class.
        /// </summary>
        /// <param name="contentManager">The content manager.</param>
        /// <param name="geographicManager">The geographic manager.</param>
        /// <param name="mediaManager">The media manager.</param>
        /// <param name="resourceManager">The resource manager.</param>
        public MainViewModel(
            IContentManager contentManager,
            IGeographicManager geographicManager,
            IMediaManager mediaManager,
            IResourceManager resourceManager)
        {
            this.contentManager = contentManager;
            this.geographicManager = geographicManager;
            this.mediaManager = mediaManager;
            this.resourceManager = resourceManager;

            this.WireEvents();
            this.WireCommands();
            this.WireLocalization();

            this.contentManager.GetContentItems();
        }

        /// <summary>
        /// Gets a collection for ItemViewModel objects.
        /// </summary>
        public IEnumerable<ItemViewModel> Items { get; private set; }

        /// <summary>
        /// Gets or sets the selected item.
        /// </summary>
        /// <value>The selected item.</value>
        [PropertyChanged]
        public ItemViewModel SelectedItem { get; set; }

        /// <summary>
        /// Gets or sets the location.
        /// </summary>
        /// <value>The location.</value>
        [PropertyChanged]
        public string LocationText { get; set; }

        /// <summary>
        /// Gets or sets the get location menu item text.
        /// </summary>
        /// <value>The get location menu item text.</value>
        [PropertyChanged]
        public string TrackLocationMenuItemText { get; set; }

        /// <summary>
        /// Gets or sets the get location menu item text.
        /// </summary>
        /// <value>The get location menu item text.</value>
        [PropertyChanged]
        public string RecordingMenuItemText { get; set; }

        /// <summary>
        /// Gets or sets the message command.
        /// </summary>
        /// <value>The message command.</value>
        public ICommand ListItemMessageCommand { get; private set; }

        /// <summary>
        /// Gets or sets the get location command.
        /// </summary>
        /// <value>The get location command.</value>
        public ICommand LocationTrackingCommand { get; private set; }

        /// <summary>
        /// Gets or sets the recording command.
        /// </summary>
        /// <value>The recording command.</value>
        public ICommand RecordingCommand { get; private set; }

        /// <summary>
        /// Gets or sets the menu item message command.
        /// </summary>
        /// <value>The menu item message command.</value>
        public ICommand MenuItemMessageCommand { get; private set; }

        /// <summary>
        /// Wires the localization.
        /// </summary>
        private void WireLocalization()
        {
            this.TrackLocationMenuItemText = this.resourceManager.GetStringResource<Global>(ResourceKey.StartTrackingLocation);
            this.RecordingMenuItemText = this.resourceManager.GetStringResource<Global>(ResourceKey.StartRecording);
        }

        /// <summary>
        /// Wires the events.
        /// </summary>
        private void WireEvents()
        {
            this.contentManager.GetContentItemsCompleted += this.ContentManagerGetContentItemsCompleted;

            this.geographicManager.GeoWatcherPositionChanged += this.GeographicManagerGeoWatcherPositionChanged;
            this.geographicManager.GeoWatcherStarted += this.GeographicManagerGeoWatcherStarted;
            this.geographicManager.GeoWatcherStopped += this.GeographicManagerGeoWatcherStopped;

            this.mediaManager.MicrophoneRecordingStarted += this.MediaManagerMicrophoneRecordingStarted;
            this.mediaManager.MicrophoneRecordingStopped += this.MediaManagerMicrophoneRecordingStopped;
        }

        /// <summary>
        /// Medias the manager microphone recording stopped.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void MediaManagerMicrophoneRecordingStopped(object sender, EventArgs<MicrophoneResult> e)
        {
            this.isRecording = false;
            this.RecordingMenuItemText = this.resourceManager.GetStringResource<Global>("StartRecording");

            e.Value.SoundEffect.Play();
        }

        /// <summary>
        /// Medias the manager microphone recording started.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void MediaManagerMicrophoneRecordingStarted(object sender, EventArgs e)
        {
            this.isRecording = true;
            this.RecordingMenuItemText = this.resourceManager.GetStringResource<Global>("StopRecording");
        }

        /// <summary>
        /// Wires the commands.
        /// </summary>
        private void WireCommands()
        {
            this.ListItemMessageCommand = new RelayCommand(this.ShowListItemMessage);
            this.MenuItemMessageCommand = new RelayCommand<string>(this.ShowMenuItemMessage);
            this.LocationTrackingCommand = new RelayCommand(this.StartTrackingLocation);
            this.RecordingCommand = new RelayCommand(this.MicrophoneRecording);
        }

        /// <summary>
        /// Starts the recording.
        /// </summary>
        private void MicrophoneRecording()
        {
            if (!this.isRecording)
            {
                this.mediaManager.StartMicrophoneRecording();
            }
            else
            {
                this.mediaManager.StopMicrophoneRecording();
            }
        }

        /// <summary>
        /// Geographics the manager geo watcher stopped.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void GeographicManagerGeoWatcherStopped(object sender, EventArgs e)
        {
            this.isTrackingLocation = false;
            this.LocationText = string.Empty;
        }

        /// <summary>
        /// Geographics the manager geo watcher started.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void GeographicManagerGeoWatcherStarted(object sender, EventArgs e)
        {
            this.isTrackingLocation = true;
        }

        /// <summary>
        /// Geographics the manager geo watcher position changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The instance containing the event data.</param>
        private void GeographicManagerGeoWatcherPositionChanged(object sender, EventArgs<GeoPositionChangedEventArgs<GeoCoordinate>> e)
        {
            DispatcherHelper.UIDispatcher.BeginInvoke(() => this.LocationText = e.Value.Position.Location.ToString());
        }

        /// <summary>
        /// Starts tracking phone location.
        /// </summary>
        private void StartTrackingLocation()
        {
            if (this.isTrackingLocation)
            {
                this.geographicManager.StopGeoWatcher();
                this.TrackLocationMenuItemText = this.resourceManager.GetStringResource<Global>(ResourceKey.StartTrackingLocation);
            }
            else
            {
                this.geographicManager.StartGeoWatcher(0, GeoPositionAccuracy.Default);
                this.TrackLocationMenuItemText = this.resourceManager.GetStringResource<Global>(ResourceKey.StopTrackingLocation);
            }
        }

        /// <summary>
        /// Shows the message.
        /// </summary>
        private void ShowListItemMessage()
        {
            MessageBox.Show(this.SelectedItem.LineOne);
        }

        /// <summary>
        /// Shows the menu item message.
        /// </summary>
        /// <param name="message">The message.</param>
        private void ShowMenuItemMessage(string message)
        {
            MessageBox.Show(message);
        }

        /// <summary>
        /// Contents the manager get content items completed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The instance containing the event data.</param>
        private void ContentManagerGetContentItemsCompleted(object sender, EventArgs<IEnumerable<ItemViewModel>> e)
        {
            this.Items = e.Value;
        }
    }
}